package util.encrypt;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * Algoritmo triple DES, con clave MD5, modo ECB por defecto
 * @author Rdelacruz
 */
public class CriptoTripleDESBasico {
    
    private static final String KEY_DEFAULT = "HG58YZ3CR9";
    
    private final Cipher cipher;
    private final Cipher decipher;    
    private final boolean dataUTF8;
    
    public CriptoTripleDESBasico() 
            throws NoSuchAlgorithmException, UnsupportedEncodingException, 
            NoSuchPaddingException, InvalidKeyException, 
            InvalidAlgorithmParameterException {
        this(KEY_DEFAULT,false,true);
    }
    
    public CriptoTripleDESBasico(String key) 
            throws NoSuchAlgorithmException, UnsupportedEncodingException, 
            NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
        this(key,false,true);
    }                      
    
    public CriptoTripleDESBasico(String key, boolean keyUTF8, boolean dataUTF8) 
            throws NoSuchAlgorithmException, UnsupportedEncodingException, 
            NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
        this(key,keyUTF8,dataUTF8, ModoCifrador.ECB);//ECB por defecto
    }
            
    public CriptoTripleDESBasico(String key, boolean keyUTF8, boolean dataUTF8, ModoCifrador tipo) 
            throws NoSuchAlgorithmException, UnsupportedEncodingException, 
            NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
        this.dataUTF8 = dataUTF8;
        
        final byte[] digestOfPassword = CriptoMD5Util.hash(key,keyUTF8);
    	final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);    	
        for (int j = 0, k = 16; j < 8;) {
            keyBytes[k++] = keyBytes[j++];
    	}        
    	final SecretKey secretkey = new SecretKeySpec(keyBytes, "DESede");         
        
        switch(tipo) {
            case CBC:
                final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
                cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
                cipher.init(Cipher.ENCRYPT_MODE, secretkey, iv);
                
                //final IvParameterSpec iv = new IvParameterSpec(new byte[8]);        
                decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
                decipher.init(Cipher.DECRYPT_MODE, secretkey, iv);
                break;
            case ECB:
            default:    
                cipher = Cipher.getInstance("DESEDE/ECB/PKCS5Padding");        
                cipher.init(Cipher.ENCRYPT_MODE, secretkey);

                decipher = Cipher.getInstance("DESEDE/ECB/PKCS5Padding");
                decipher.init(Cipher.DECRYPT_MODE, secretkey);
                break;
        }
    }
    
    public byte[] encryptToBytes(final byte[] plainTextBytes) 
            throws IllegalBlockSizeException, BadPaddingException {  
        final byte[] cipherText = this.cipher.doFinal(plainTextBytes);
        
    	// final String encodedCipherText = new sun.misc.BASE64Encoder()
    	// .encode(cipherText);
    	return cipherText;
    }
        
    public byte[] encryptToBytes(String data) 
            throws NoSuchAlgorithmException, NoSuchPaddingException, 
            InvalidKeyException, UnsupportedEncodingException, 
            BadPaddingException, IllegalBlockSizeException {               
        
        final byte[] plainTextBytes;        
        if(dataUTF8) {
            plainTextBytes = data.getBytes("utf-8");
        }
        else {
            plainTextBytes = data.getBytes();
        }
        
    	return encryptToBytes(plainTextBytes);
    }
    
    public String decrypt(byte[] data) 
            throws UnsupportedEncodingException, IllegalBlockSizeException, 
            BadPaddingException {                
        // final byte[] encData = new
    	// sun.misc.BASE64Decoder().decodeBuffer(message);
    	//final byte[] plainText = decipher.doFinal(data);
    	final byte[] plainText = decryptToBytes(data);

        if(dataUTF8)
            return new String(plainText, "UTF-8");
        else
            return new String(plainText);
    }
    
    public byte[] decryptToBytes(byte[] data) throws IllegalBlockSizeException, BadPaddingException {
        return decipher.doFinal(data);
    }
            
}
